package cn.alpha.workflow.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import cn.alpha.workflow.vo.DTRequestParam;
import cn.alpha.workflow.vo.DTResponseData;
import cn.ffcs.shequ.bo.Result;

/** act_re_model：流程设计模型部署表，流程设计器设计流程后，保存数据到该表
 * 	  ID_ varchar(64) comment '',
	  REV_ int(11) comment '乐观锁',
	  NAME_ varchar(255) comment '名称',
	  KEY_ varchar(255) comment '',
	  CATEGORY_ varchar(255) comment '分类',
	  CREATE_TIME_ timestamp comment '创建时间',
	  LAST_UPDATE_TIME_ timestamp comment '最新修改时间',
	  VERSION_ int(11) comment '版本',
	  META_INFO_ varchar(4000) comment '以json格式保存流程定义的信息',
	  EDITOR_SOURCE_VALUE_ID_ varchar(64) comment 'json串，编辑器来源，外键关联act_ge_bytearray, name是source',
	  EDITOR_SOURCE_EXTRA_VALUE_ID_ varchar(64) comment '图片，外键关联act_ge_bytearray, name是source-extra',
 *
 */
@Controller("modelController")
public class ModelController extends AbstractController 
{
	/**创建模型*/
    @RequestMapping(value = "/model/import")
    @ResponseBody
    public Object importModel(MultipartFile importFile) 
    {
    	Result res=new Result();
        try {
        	byte[] bytes=importFile.getBytes();
        	String fileName=importFile.getOriginalFilename();
        	BpmnModel bpmnModel=null;
        	JsonNode editorNode=null;
        	XMLStreamReader xmlStreamReader=null;
        	boolean jsonXml=fileName.endsWith("json");
        	
        	if(jsonXml)
        	{
        		BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
        		editorNode = new ObjectMapper().readTree(bytes);
                bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
        	}
        	else 
        	{
        		BpmnXMLConverter xmlConverter=new BpmnXMLConverter();
        		xmlStreamReader=XMLInputFactory.newInstance().createXMLStreamReader(new ByteArrayInputStream(bytes));
        		bpmnModel = xmlConverter.convertToBpmnModel(xmlStreamReader);
        	}
        	
        	
            org.activiti.bpmn.model.Process process=bpmnModel.getMainProcess();
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode modelObjectNode = objectMapper.createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, process.getName());
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            
            Model modelData = repositoryService.newModel();
            modelData.setName(process.getName());
            modelData.setKey(process.getId());
            modelData.setMetaInfo(modelObjectNode.toString());
            repositoryService.saveModel(modelData);
            repositoryService.addModelEditorSource(modelData.getId(), bytes);
            res.setResult(modelData.getId());
        } catch (Exception e) {
            logger.error("导入模型失败：", e);
            res.setNote(e.getMessage());
        }
        return res;
    }
	
	
	@RequestMapping(value = "/model/export")
    public void export(String modelId,String type,HttpServletResponse response) 
	{
        try {
            Model modelData = repositoryService.getModel(modelId);
            BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
            byte[] modelEditorSource = repositoryService.getModelEditorSource(modelData.getId());

            JsonNode editorNode = new ObjectMapper().readTree(modelEditorSource);
            BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);

            // 处理异常
            if (bpmnModel.getMainProcess() == null) {
                response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY.value());
                response.getOutputStream().println("model has errors, can't export!");
                response.flushBuffer();
                return;
            }

            String fileName = "";
            byte[] exportBytes = null;
            String mainProcessId = bpmnModel.getMainProcess().getId();
            if (type.equals("bpmn")) 
            {
                BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
                exportBytes = xmlConverter.convertToXML(bpmnModel);
                fileName = mainProcessId + ".bpmn20.xml";
            } 
            else if (type.equals("json")) 
            {
                exportBytes = modelEditorSource;
                fileName = mainProcessId + ".json";
            }

            response.reset();
    		response.setCharacterEncoding("utf-8");  
            response.setContentType("multipart/form-data");  
            response.setContentType("application/octet-stream");
            response.setContentLength(exportBytes.length);
            response.setHeader("Content-Disposition", "attachment;fileName="+ fileName);
            response.flushBuffer();
            
            ByteArrayInputStream in = new ByteArrayInputStream(exportBytes);
            IOUtils.copy(in, response.getOutputStream());

        } catch (Exception e) {
            logger.error("导出model文件失败：modelId={}, type={}", modelId, type, e);
        }
    }
	
	//查看
	@RequestMapping(value = "/model/view")
    public void view(String modelId,HttpServletResponse response) throws IOException 
	{
        // 输出资源内容到相应对象
        byte[] b = repositoryService.getModelEditorSourceExtra(modelId);
        if(b!=null)
        {
        	 ByteArrayInputStream in = new ByteArrayInputStream(b);
             IOUtils.copy(in, response.getOutputStream());
        }
	}
	
	@RequestMapping(value = "/model/deploy")
	@ResponseBody
    public Object deploy(String modelId) 
	{
		Result res=new Result();
		try {
            Model modelData = repositoryService.getModel(modelId);
            ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
            
            byte[] bpmnBytes = null;
            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            bpmnBytes = new BpmnXMLConverter().convertToXML(model);

            String processName = modelData.getName() + ".bpmn20.xml";
            Deployment deployment = repositoryService.createDeployment()
            		.name(modelData.getName()).category(modelData.getCategory())
            		.addString(processName, new String(bpmnBytes)).deploy();
            res.setResult(deployment.getId());
        } catch (Exception e) {
            logger.error("根据模型部署流程失败：modelId={}", modelId, e);
            res.setNote(e.getMessage());
        }
        return res;
    }
	
	@RequestMapping(value = "/model/delete")
	@ResponseBody
    public Object delete(String modelId) 
	{
		Result res=new Result();
        repositoryService.deleteModel(modelId);
        res.setResult(modelId);
        return res;
    }
	
	/**创建模型*/
    @RequestMapping(value = "/model/save")
    @ResponseBody
    public Object create(String name,String key,String description,String category) 
    {
    	Result res=new Result();
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode editorNode = objectMapper.createObjectNode();
            editorNode.put("id", "canvas");
            editorNode.put("resourceId", "canvas");
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.put("stencilset", stencilSetNode);
            
            Model modelData = repositoryService.newModel();
            ObjectNode modelObjectNode = objectMapper.createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            description = StringUtils.defaultString(description);
            modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
            modelData.setMetaInfo(modelObjectNode.toString());
            modelData.setName(name);
            modelData.setKey(key);
            modelData.setCategory(category);

            repositoryService.saveModel(modelData);
            repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
            res.setResult(modelData.getId());
        } catch (Exception e) {
            logger.error("创建模型失败：", e);
            res.setNote(e.getMessage());
        }
        return res;
    }

	/*** 模型列表  */
    @RequestMapping(value = "/model/list")
    @ResponseBody
    public Object list(@RequestBody DTRequestParam dtRequestParam) 
    {
    	ModelQuery modelQuery=repositoryService.createModelQuery();
    	String searchStr=dtRequestParam.getSearch().getValue();
    	if(!StringUtils.isEmpty(searchStr))
    		modelQuery.modelNameLike("%"+searchStr+"%");
    	List<Model> modelList=modelQuery.orderByModelId().desc()
    			.listPage(dtRequestParam.getStart(),dtRequestParam.getLength());
    	Long total=modelQuery.count();
    	return new DTResponseData(modelList, total, dtRequestParam.getDraw());
    }
	
}
